/*
Copyright IBM Corp. 2016 All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

		 http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

//WARNING - this chaincode's ID is hard-coded in chaincode_example04 to illustrate one way of
//calling chaincode from a chaincode. If this example is modified, chaincode_example04.go has
//to be modified as well with the new ID of chaincode_example02.
//chaincode_example05 show's how chaincode ID can be passed in as a parameter instead of
//hard-coding.

import (
	"encoding/json"
	"fmt"

	"github.com/hyperledger/fabric/core/chaincode/shim"
	pb "github.com/hyperledger/fabric/protos/peer"
)

// SimpleKvStoreChaincode example simple Chaincode implementation
type SimpleKvStoreChaincode struct {
}

const (
	CHAINNAME = "KvStore"
	VERSION   = "v2.0"
)

func (t *SimpleKvStoreChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response {
	return shim.Success(nil)
}

func (t *SimpleKvStoreChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
	fmt.Println(getVersion() + "switch Invoke fun")
	function, args := stub.GetFunctionAndParameters()
	switch function {
	case "add":
		return t.addKvStore(stub, args)
	case "query":
		return t.query(stub, args)
	case "history":
		return t.getHistory(stub, args)
	case "delete":
		return t.delete(stub, args)
	// case "range":
	// 	return t.rangeByKey(stub, args)
	default:
		return shim.Error("Invalid  " + getVersion() + "invoke function name. Expecting \"add\" \"query\"")
	}
}

func getVersion() string {
	return CHAINNAME + " " + VERSION + " "
}

// Add kv store k v
func (t *SimpleKvStoreChaincode) addKvStore(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	var key, value string // Entities
	var err error

	if len(args) != 2 {
		jsonResp := "{\"Error\":" + getVersion() + "\"Incorrect number of arguments. Expecting 2\"}"
		return shim.Error(jsonResp)
	}

	key = args[0]
	value = args[1]

	err = stub.PutState(key, []byte(value))
	if err != nil {
		return shim.Error(getVersion() + ":" + err.Error())
	}
	// jsonResp := "{\"Sccess\":" + getVersion() + "\"add KvStore\"}"
	return shim.Success(nil)
}

// get history
func (t *SimpleKvStoreChaincode) getHistory(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	var key string // Entities
	var err error

	if len(args) != 1 {
		jsonResp := "{\"Error\":" + getVersion() + "\"Incorrect number of arguments. Expecting 2\"}"
		return shim.Error(jsonResp)
	}

	key = args[0]
	b, err := stub.GetState(key)
	if err != nil {
		jsonResp := "{\"Error\":" + getVersion() + "\"Failed to get key \"}"
		return shim.Error(jsonResp)
	}

	if b == nil {
		jsonResp := "{\"Error\":" + getVersion() + "\"Failed history is null\"}"
		return shim.Error(jsonResp)
	}

	// 获取历史变更数据
	iterator, err := stub.GetHistoryForKey(key)
	if err != nil {
		jsonResp := "{\"Error\":" + getVersion() + "\"Failed to search history\"}"
		return shim.Error(jsonResp)
	}
	defer iterator.Close()

	// 迭代处理
	var historys []string
	for iterator.HasNext() {
		hisData, err := iterator.Next()
		if err != nil {
			return shim.Error(getVersion() + "Failed to get history data")
			jsonResp := "{\"Error\":" + getVersion() + "\"Failed to get history data\"}"
			return shim.Error(jsonResp)
		}
		// hisData.TxId
		// hisData.Value
		historys = append(historys, string(hisData.Value))
	}

	result, err := json.Marshal(historys)
	if err != nil {
		return shim.Error(getVersion() + "Failed to json marshal")
	}
	return shim.Success(result)
}

// Deletes an entity from state
func (t *SimpleKvStoreChaincode) delete(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	if len(args) != 1 {
		jsonResp := "{\"Error\":\"Incorrect number of arguments. Expecting 1\"}"
		return shim.Error(jsonResp)
	}

	key := args[0]

	// Delete the key from the state in ledger
	err := stub.DelState(key)
	if err != nil {
		jsonResp := "{\"Error\":\"Failed to delete state\"}"
		return shim.Error(jsonResp)
	}

	return shim.Success(nil)
}

// query callback representing the query of a chaincode
func (t *SimpleKvStoreChaincode) query(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	var A string // Entities
	var err error

	if len(args) != 1 {
		jsonResp := "{\"Error\":\"Incorrect number of arguments. Expecting name of the person to query\"}"
		return shim.Error(jsonResp)
	}

	A = args[0]

	Avalbytes, err := stub.GetState(A)
	if err != nil {
		jsonResp := "{\"Error\":\"Failed to get state for " + A + "\"}"
		return shim.Error(jsonResp)
	}

	if Avalbytes == nil {
		jsonResp := "{\"Error\":\"Nil query for " + A + "\"}"
		return shim.Error(jsonResp)
	}
	return shim.Success(Avalbytes)
}

// func (t *SimpleKvStoreChaincode) rangeByKey(stub shim.ChaincodeStubInterface, args []string) pb.Response {
// 	resultIterator, _ := stub.GetStateByRange(args[0],args[1])
// 	defer resultIterator.Close()
// 	// fmt.Println("GetStateByRange获取从key为str0到key为str2的值，返回k-v的迭代器，遍历：")

// 	var ranges []string
// 	for resultIterator.HasNext() {
// 		item, _ := resultIterator.Next()
// 		fmt.Println(string(item.Key), string(item.Value))
// 		ranges = append(ranges, string(item.Value))
// 	}

// 	result, err := json.Marshal(ranges)
// 	if err != nil {
// 		return shim.Error(getVersion() + "Failed to json marshal")
// 	}
// 	return shim.Success(result)
// }

func main() {
	err := shim.Start(new(SimpleKvStoreChaincode))
	if err != nil {
		fmt.Printf("Error starting Simple chaincode: %s", err)
	}
}
